/*
 * Copyright 2009 (c) Patrick Pietens.
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */
package indigo.motion 
{
	import indigo.utils.DisposableEventDispatcher;

	import flash.display.DisplayObject;
	import flash.events.Event;

	/**
	 * Dispatches when the in-animation of a Motion is finished
	 * @eventType indigo.motion.events.MotionEvent
	 */
	[Event(name="animateInFinished", type="indigo.motion.MotionEvent")]

	/**
	 * Dispatches when the out-animation of a Motion is finished
	 * @eventType indigo.motion.events.MotionEvent
	 */
	[Event(name="animateOutFinished", type="indigo.motion.MotionEvent")]
	/**
	 * The <code>Motion</code> class handles the animation of your DisplayObject. It is a Decorator for DisplayObjects
	 * It extends the target <code>DisplayObject</code> with an <code>animateIn</code> and <code>animateOut</code> method. 
	 * Extend and overwrite these methods to create <code>Motions</code>.
	 * 
	 * @example
	 * <code>
	 * <listing version="3.0" >
	 * <pre>package  
	 * {
	 * 		import indigo.motion.Motion;
	 *		import indigo.motion.MotionEvent;
	 *
	 *		import flash.display.Sprite;
	 *		public class MySprite extends Sprite 
	 *		{
	 *			private var _motion:Motion;
	 *			
	 *			public function MySprite()
	 *			{
	 *				alpha = 0.0;
	 *							
	 *				_motion = new FadeMotion( this );
	 *				_motion.addEventListener( MotionEvent.ANIMATE_IN_FINISHED, this.onAnimateIn, false, 0, true );
	 *				_motion.animateIn( );
	 *			}
	 *			private function onAnimateIn( event:MotionEvent ):void
	 *			{
	 *				_motion = new SlideMotion( this );
	 *				_motion.animateOut( );
	 *			}
	 *		}
	 *	}
	 *	
	 *	import indigo.motion.Motion;
	 *
	 *	import gs.TweenLite;
	 *	import gs.easing.*;
	 *
	 *	class FadeMotion extends Motion
	 *	{
	 *		override public function animateIn( delay:Number = 0.0 ):void
	 *		{
	 *			TweenLite.to( this.target, 0.15, { alpha: 1.0, ease: Linear.easeNone, onComplete: this.onAnimateIn } );
	 *		}	
	 *		override public function animateIn( delay:Number = 0.0 ):void
	 *		{
	 *			TweenLite.to( this.target, 0.15, { alpha: 0.0, ease: Linear.easeNone, onComplete: this.onAnimateOut } );
	 *		}	
	 *	}
	 *		
	 *	class SlideMotion extends Motion
	 *	{
	 *		override public function animateIn( delay:Number = 0.0 ):void
	 *		{
	 *			this.target.x -= 60;
	 *			TweenLite.to( this.target, 0.45, { x: this.target.x, ease: Sine.easeIn, onComplete: this.onAnimateIn } );
	 *		}	
	 *		override public function animateIn( delay:Number = 0.0 ):void
	 *		{
	 *			TweenLite.to( this.target, 0.45, { x: this.target.x + 60, ease: Back.easeOut, onComplete: this.onAnimateOut } );
	 *		}	
	 *	}
	 * </pre>
	 * </listing>
	 * </code>
	 * 
	 * @playerversion Flash 9
	 * @langversion ActionScript 3.0
	 */
	public class Motion extends DisposableEventDispatcher
	{
		/**
		 * Reference to the motion its target displayObject
		 */
		private var _target:DisplayObject;
		/**
		 * Boolean that indicates the target is animating
		 */
		protected var _isRunning:Boolean = false;

		
		/**
		 * Constructor
		 * 
		 */
		public function Motion( target:DisplayObject ):void
		{
			this._target = target;
		}

		
		/**
		 * Plays the animate-out effect on the target <code>DisplayObject</code>
		 * @param Number that indicates the delay of the animation
		 * 
		 */
		public function animateIn( delay:Number = 0.0 ):void
		{
			this._isRunning = true;
			this._target.visible = true;			this.onAnimateIn( );
		}

		
		/**
		 * Executes when the in-animation is finished
		 * @param Number that indicates the delay of the animation
		 * 
		 */
		protected function onAnimateIn( event:Event = null ):void
		{
			this._isRunning = false;
			
			var myEvent:MotionEvent = new MotionEvent( MotionEvent.ANIMATE_IN_FINISHED );
			this.dispatchEvent( myEvent );
		}

		
		/**
		 * Plays the animate-in effect on the target <code>DisplayObject</code>
		 * @param Number that indicates the delay of the animation
		 * 
		 */		
		public function animateOut( delay:Number = 0.0 ):void
		{
			this._isRunning = true;			this._target.visible = false;
			this.onAnimateOut( );
		}		

		
		/**
		 * Executes when the out-animation is finished
		 * @param Number that indicates the delay of the animation
		 * 
		 */
		protected function onAnimateOut( event:Event = null ):void
		{
			this._isRunning = false;
			
			var myEvent:MotionEvent = new MotionEvent( MotionEvent.ANIMATE_OUT_FINISHED );
			this.dispatchEvent( myEvent );
		}		

		
		/**
		 * Reference of the target <code>DisplayObject</code> which is affected by the <code>Motion</code>
		 * 
		 */
		public function get target():DisplayObject
		{
			return this._target;
		}

		
		/**
		 * Boolean that indicates the target is animating
		 * 
		 */
		public function get isRunning():Boolean
		{
			return this._isRunning;
		}

		
		/**
		 * @inheritDoc
		 * 
		 */		
		override public function dispose( event:Event = null ):void
		{
			log( "Disposing motion attached to " + this.target );
			
			super.dispose( event );
			this._target = null;
		}
	}
}
